package controller;


import java.util.ArrayList;
import java.util.Calendar;

import model.Customer;
import model.Discount;
import model.Employee;
import model.Movie;
import model.Sale;
import model.Sale.STATUS;
import model.Seat;
import model.ShowTime;
import model.Ticket;
import database.DBDiscount;
import database.DBSale;
import database.DBSeat;
import database.DBTicket;

/**
 * 
 * @author Anders
 *
 */
public class CtrSale 
{
	private CtrShowTime ctrShowTime;
	private DBTicket dbt;
	private DBSale dbs;
	private DBSeat dbseat;
	
	public CtrSale()
	{
		ctrShowTime = new CtrShowTime();
		dbt = new DBTicket();
		dbs = new DBSale();
		dbseat = new DBSeat();
	}
	
	public ArrayList<StatusSeat> findSeats(ShowTime s)
	{
		ArrayList<StatusSeat> result = new ArrayList<StatusSeat>();
		
		ArrayList<Ticket> tickets = dbt.findTickets(s);
		for(Ticket t : tickets) {
			StatusSeat statSeat = null;
			if(t.getSale().getStatus() == STATUS.RESERVED)
			{
				statSeat = new StatusSeat(t.getSeat(), s.getCinema(), s, StatusSeat.STATUS.RESERVED);
			}
			else if(t.getSale().getStatus() == STATUS.SOLD)
			{
				statSeat = new StatusSeat(t.getSeat(), s.getCinema(), s, StatusSeat.STATUS.SOLD);
			}
			result.add(statSeat);
		}
		
		ArrayList<Seat> seats = dbseat.getAllSeats(s.getCinema().getNumber());
		for(Seat seat : seats) {
			
			boolean found = false;
			int index = 0;
			int end = result.size();
			while(!found && index < end) {
				if(seat.equals(result.get(index).getSeat())) {
					found = true;
				}
				else {
					index++;
				}
			}
			
			if(!found) {
				StatusSeat statseat = new StatusSeat(seat, s.getCinema(), s, StatusSeat.STATUS.FREE);
				result.add(statseat);
			}
		}
		
		return result;
	}
	
	public Sale sellSeats(ArrayList<StatusSeat> seatsToSell, Customer customer, model.Sale.STATUS saleStatus) throws SeatOccupiedException
	{
		Calendar cal = Calendar.getInstance();
		int saleID = dbs.getMaxID() + 1;
		Sale sale = new Sale(saleID, cal.get(Calendar.DAY_OF_MONTH), cal.get(Calendar.MONTH), cal.get(Calendar.YEAR), saleStatus, CtrEmployee.getInstance().getEmployeeLogedOn());
	
		//has any of the seats already been taken?
		for(StatusSeat ss :seatsToSell) {
			ArrayList<StatusSeat> allreadySoldSeats = findSeats(ss.getShowTime());
			if(allreadySoldSeats.contains(ss) && ss.getStatus() != StatusSeat.STATUS.FREE) {
				throw new SeatOccupiedException(String.format("Seat row %d number %d has already been sold!", ss.getSeat().getRow(), ss.getSeat().getNumber()));
			}
		}
		
		//make the sale:
		dbs.addSale(sale, customer);
		
		//and add the tickets to that sale
		for(StatusSeat ss : seatsToSell) {
			dbt.addTicket(ss.getSeat(), ss.getShowTime(), sale);
		}
		
		return sale;
		
	}
	
	public void addDiscountsToSale(ArrayList<Discount> discounts)
	{
		DBDiscount dbDiscount = new DBDiscount();
		for(Discount discount : discounts) {
			dbDiscount.addDiscount(discount);
		}
	}

	/**
	 * @author Allan Malka
	 * Creates a sale object for quicksale and saves it in the database
	 * @param seat
	 * @param showTime
	 * @param emp
	 * @param status
	 * @return true if seat is free. False if the seat is taken reserved or sold.
	 */
	public boolean sellSeat(Seat seat, ShowTime showTime)
	{
		Employee emp = CtrEmployee.getInstance().getEmployeeLogedOn();
		
		boolean freeSeat = true;
		
		for(StatusSeat ss : findSeats(showTime)) {
			if(ss.getSeat().equals(seat)) {	
				if(ss.getStatus() == StatusSeat.STATUS.FREE) {
					Calendar cal = Calendar.getInstance();
					int saleID = dbs.getMaxID() + 1;
					Sale s = new Sale(saleID, cal.get(Calendar.DAY_OF_MONTH), cal.get(Calendar.MONTH), cal.get(Calendar.YEAR), STATUS.SOLD, emp);
					dbs.addSale(s, null);
					dbt.addTicket(seat, showTime, s);
				}
				else {
					freeSeat = false;
				}
			}
		}

		return freeSeat;
	}
	
	public Sale createSale(int id, int day, int month, int year, Employee emp)
	{
		STATUS stat = STATUS.RESERVED;
		Sale s = new Sale(id, day, month, year, stat, emp);
		return s;
	}
	
	/** 
	 * Sorts every ShowTime under the movie belonging to it
	 * @return a list of "movies" (ie ArrayList of ShowTime w/ same movie)
	 */
	public ArrayList<ArrayList<ShowTime>> getSortedShowTimes()
	{
		ArrayList<ArrayList<ShowTime>> result = new ArrayList<ArrayList<ShowTime>>();
		
		ArrayList<ShowTime> allShowTimes = ctrShowTime.getAllShowTimes();
		
		ArrayList<Movie> allMovies = new ArrayList<Movie>();
		
		//load all different movies into an arraylist
		for(ShowTime st : allShowTimes) {
			if(! allMovies.contains(st.getMovie())) {
				allMovies.add(st.getMovie());
			}
		}
		
		// if showtime.getmovie matches the current movie, then add that showtime to movieShowTime
		for(Movie m : allMovies) {
			ArrayList<ShowTime> movieShowTime = new ArrayList<ShowTime>();
			
			for(ShowTime st : allShowTimes) {
				if(st.getMovie().getId() == m.getId()) {
					movieShowTime.add(st);
				}
			}
			
			//and add the collection of showtimes sorted by movie to the arraylist
			result.add(movieShowTime);
		}
		
		//return the sorted (by movie) showtimes
		return result;
	}
	
	public void deleteReservation(String custPhone)
	{
		dbs.deleteReservationByPhone(custPhone);
	}
	
	public class SeatOccupiedException extends Exception
	{
		private String message;
		public SeatOccupiedException(String message)
		{
			this.message = message;
		}
		
		@Override
		public void printStackTrace()
		{
			System.out.println(message);
			super.printStackTrace();
		}
		
		public String getMessage()
		{
			return message;
		}
	}

	public ArrayList<Ticket> getTickets(ArrayList<StatusSeat> statusSeats)
	{
		ArrayList<Ticket> result = new ArrayList<Ticket>();
		
		ArrayList<ShowTime> previousShowTimes = new ArrayList<ShowTime>();
		
		for(StatusSeat sSeat : statusSeats) {
			
			ShowTime seatShowTime = sSeat.getShowTime();
			
			//have we already checked this showtime?
			if(! previousShowTimes.contains(seatShowTime)) {
				
				ArrayList<Ticket> ticketsToShowTime = dbt.findTickets(seatShowTime);
				
				for(Ticket ticket : ticketsToShowTime) {
					
					if(ticket.getSeat().equals(sSeat.getSeat())) {
						
						result.add(ticket);
					}
				}
				previousShowTimes.add(seatShowTime);
			}
			
		}

		return result;
	}
}
